Utforska alternativ till TypeScript-enums, inklusive konstanta pÄstÄenden och uniontyper. LÀr dig nÀr du ska anvÀnda respektive för optimal kodunderhÄll och prestanda.
TypeScript Enum-alternativ: Konstanta pÄstÄenden kontra uniontyper
TypeScript's enum Àr en kraftfull funktion för att definiera en uppsÀttning namngivna konstanter. Det Àr dock inte alltid det bÀsta valet. Denna artikel utforskar alternativ till enums, specifikt konstanta pÄstÄenden och uniontyper, och ger vÀgledning om nÀr man ska anvÀnda respektive för optimal kodkvalitet, underhÄllbarhet och prestanda. Vi kommer att fördjupa oss i nyanserna av varje tillvÀgagÄngssÀtt, erbjuda praktiska exempel och ta upp vanliga problem.
FörstÄ TypeScript Enums
Innan vi dyker in i alternativen, lÄt oss snabbt granska TypeScript enums. En enum Àr ett sÀtt att definiera en uppsÀttning namngivna numeriska konstanter. Som standard tilldelas det första enum-medlemmen vÀrdet 0, och efterföljande medlemmar ökas med 1.
enum Status {
Pending,
InProgress,
Completed,
Rejected,
}
const currentStatus: Status = Status.InProgress; // currentStatus kommer att vara 1
Du kan ocksÄ explicit tilldela vÀrden till enum-medlemmar:
enum HTTPStatus {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
Forbidden = 403,
NotFound = 404,
}
const serverResponse: HTTPStatus = HTTPStatus.OK; // serverResponse kommer att vara 200
Fördelar med Enums
- LÀslighet: Enums förbÀttrar kodens lÀslighet genom att tillhandahÄlla meningsfulla namn för numeriska konstanter.
- TypsÀkerhet: De sÀkerstÀller typsÀkerhet genom att begrÀnsa vÀrden till de definierade enum-medlemmarna.
- Autokomplettering: IDE:er tillhandahÄller förslag för autokomplettering av enum-medlemmar, vilket minskar fel.
Nackdelar med Enums
- Runtime-overhead: Enums kompileras till JavaScript-objekt, vilket kan introducera runtime-overhead, sÀrskilt i stora applikationer.
- Mutation: Enums Ă€r muterbara som standard. Ăven om TypeScript tillhandahĂ„ller
const enumför att förhindra mutation, har det begrÀnsningar. - OmvÀnd mappning: Numeriska enums skapar en omvÀnd mappning (t.ex.
Status[1]returnerar "InProgress"), vilket ofta Àr onödigt och kan öka bundle-storleken.
Alternativ 1: Konstanta pÄstÄenden
Konstanta pÄstÄenden ger ett sÀtt att skapa oförÀnderliga, skrivskyddade datastrukturer. De kan anvÀndas som ett alternativ till enums i mÄnga fall, sÀrskilt nÀr du behöver en enkel uppsÀttning strÀng- eller numeriska konstanter.
const Status = {
Pending: 'pending',
InProgress: 'in_progress',
Completed: 'completed',
Rejected: 'rejected',
} as const;
// Typescript hÀrleder följande typ:
// {
// readonly Pending: "pending";
// readonly InProgress: "in_progress";
// readonly Completed: "completed";
// readonly Rejected: "rejected";
// }
type StatusType = typeof Status[keyof typeof Status]; // 'pending' | 'in_progress' | 'completed' | 'rejected'
function processStatus(status: StatusType) {
console.log(`Processing status: ${status}`);
}
processStatus(Status.InProgress); // Giltig
// processStatus('invalid'); // Fel: Argument av typen '"invalid"' kan inte tilldelas parameter av typen 'StatusType'.
I det hÀr exemplet definierar vi ett rent JavaScript-objekt med strÀngvÀrden. PÄstÄendet as const sÀger till TypeScript att behandla detta objekt som skrivskyddat och hÀrleda de mest specifika typerna för dess egenskaper. Vi extraherar sedan en uniontyp frÄn nycklarna. Detta tillvÀgagÄngssÀtt erbjuder flera fördelar:
Fördelar med konstanta pÄstÄenden
- OförÀnderlighet: Konstanta pÄstÄenden skapar oförÀnderliga datastrukturer, vilket förhindrar oavsiktliga Àndringar.
- Ingen Runtime-overhead: De Àr enkla JavaScript-objekt, sÄ det finns ingen runtime-overhead associerad med enums.
- TypsÀkerhet: De tillhandahÄller stark typsÀkerhet genom att begrÀnsa vÀrden till de definierade konstanterna.
- Tree-shaking vÀnligt: Moderna bundlers kan enkelt tree-shake:a oanvÀnda vÀrden, vilket minskar bundle-storleken.
ĂvervĂ€ganden för konstanta pĂ„stĂ„enden
- Mer verbose: Att definiera och typa kan vara nÄgot mer verbose Àn enums, sÀrskilt för enkla fall.
- Ingen omvÀnd mappning: De tillhandahÄller ingen omvÀnd mappning, men detta Àr ofta en fördel snarare Àn en nackdel.
Alternativ 2: Uniontyper
Uniontyper lÄter dig definiera en variabel som kan innehÄlla en av flera möjliga typer. De Àr ett mer direkt sÀtt att definiera de tillÄtna vÀrdena utan ett objekt, vilket Àr fördelaktigt nÀr du inte behöver nyckel-vÀrde-förhÄllandet som en enum eller ett konstant pÄstÄende.
type Status = 'pending' | 'in_progress' | 'completed' | 'rejected';
function processStatus(status: Status) {
console.log(`Processing status: ${status}`);
}
processStatus('in_progress'); // Giltig
// processStatus('invalid'); // Fel: Argument av typen '"invalid"' kan inte tilldelas parameter av typen 'Status'.
Detta Àr ett kortfattat och typsÀkert sÀtt att definiera en uppsÀttning tillÄtna vÀrden.
Fördelar med Uniontyper
- Kortfattat: Uniontyper Àr det mest kortfattade tillvÀgagÄngssÀttet, sÀrskilt för enkla uppsÀttningar av strÀng- eller numeriska konstanter.
- TypsÀkerhet: De tillhandahÄller stark typsÀkerhet genom att begrÀnsa vÀrden till de definierade alternativen.
- Ingen Runtime-overhead: Uniontyper existerar endast vid kompilering och har ingen runtime-representation.
ĂvervĂ€ganden för Uniontyper
- Ingen nyckel-vÀrde-association: De tillhandahÄller ingen nyckel-vÀrde-relation som enums eller konstanta pÄstÄenden. Detta innebÀr att du inte enkelt kan slÄ upp ett vÀrde med dess namn.
- Upprepning av strÀngliteral: Du kan behöva upprepa strÀngliteraler om du anvÀnder samma uppsÀttning vÀrden pÄ flera stÀllen. Detta kan mildras med en delad
type-definition.
NÀr ska man anvÀnda vilken?
Den bÀsta metoden beror pÄ dina specifika behov och prioriteringar. HÀr Àr en guide som hjÀlper dig att vÀlja:
- AnvÀnd Enums NÀr:
- Du behöver en enkel uppsÀttning numeriska konstanter med implicit inkrementering.
- Du behöver omvÀnd mappning (Àven om detta sÀllan Àr nödvÀndigt).
- Du arbetar med Àldre kod som redan anvÀnder enums i stor utstrÀckning och du har inget brÄdskande behov av att Àndra den.
- AnvÀnd konstanta pÄstÄenden NÀr:
- Du behöver en uppsÀttning strÀng- eller numeriska konstanter som ska vara oförÀnderliga.
- Du behöver en nyckel-vÀrde-relation och vill undvika runtime-overhead.
- Tree-shaking och bundle-storlek Àr viktiga övervÀganden.
- AnvÀnd Uniontyper NÀr:
- Du behöver ett enkelt, kortfattat sÀtt att definiera en uppsÀttning tillÄtna vÀrden.
- Du behöver ingen nyckel-vÀrde-relation.
- Prestanda och bundle-storlek Àr kritiska.
Exempelscenario: Definiera anvÀndarroller
LÄt oss övervÀga ett scenario dÀr du behöver definiera anvÀndarroller i en applikation. Du kan ha roller som "Admin", "Editor" och "Viewer".
AnvÀnda Enums:
enum UserRole {
Admin,
Editor,
Viewer,
}
function authorize(role: UserRole) {
// ...
}
AnvÀnda konstanta pÄstÄenden:
const UserRole = {
Admin: 'admin',
Editor: 'editor',
Viewer: 'viewer',
} as const;
type UserRoleType = typeof UserRole[keyof typeof UserRole];
function authorize(role: UserRoleType) {
// ...
}
AnvÀnda Uniontyper:
type UserRole = 'admin' | 'editor' | 'viewer';
function authorize(role: UserRole) {
// ...
}
I detta scenario erbjuder uniontyper den mest kortfattade och effektiva lösningen. Konstanta pÄstÄenden Àr ett bra alternativ om du föredrar en nyckel-vÀrde-relation, kanske för att slÄ upp beskrivningar av varje roll. Enums rekommenderas i allmÀnhet inte hÀr om du inte har ett specifikt behov av numeriska vÀrden eller omvÀnd mappning.
Exempelscenario: Definiera API-slutpunktens statuskoder
LÄt oss övervÀga ett scenario dÀr du behöver definiera API-slutpunktens statuskoder. Du kan ha koder som 200 (OK), 400 (Bad Request), 401 (Unauthorized) och 500 (Internal Server Error).
AnvÀnda Enums:
enum StatusCode {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
InternalServerError = 500
}
function processStatus(code: StatusCode) {
// ...
}
AnvÀnda konstanta pÄstÄenden:
const StatusCode = {
OK: 200,
BadRequest: 400,
Unauthorized: 401,
InternalServerError: 500
} as const;
type StatusCodeType = typeof StatusCode[keyof typeof StatusCode];
function processStatus(code: StatusCodeType) {
// ...
}
AnvÀnda Uniontyper:
type StatusCode = 200 | 400 | 401 | 500;
function processStatus(code: StatusCode) {
// ...
}
à terigen erbjuder uniontyper den mest kortfattade och effektiva lösningen. Konstanta pÄstÄenden Àr ett starkt alternativ och kan föredras dÄ de ger en mer utförlig beskrivning för en given statuskod. Enums kan vara anvÀndbara om externa bibliotek eller API:er förvÀntar sig heltalsbaserade statuskoder, och du vill sÀkerstÀlla sömlös integration. De numeriska vÀrdena överensstÀmmer med standard HTTP-koder, vilket potentiellt förenklar interaktionen med befintliga system.
PrestandaövervÀganden
I de flesta fall Àr prestandaskillnaden mellan enums, konstanta pÄstÄenden och uniontyper försumbar. Men i prestandakritiska applikationer Àr det viktigt att vara medveten om de potentiella skillnaderna.
- Enums: Enums introducerar runtime-overhead pÄ grund av skapandet av JavaScript-objekt. Denna overhead kan vara betydande i stora applikationer med mÄnga enums.
- Konstanta pÄstÄenden: Konstanta pÄstÄenden har ingen runtime-overhead. De Àr enkla JavaScript-objekt som behandlas som skrivskyddade av TypeScript.
- Uniontyper: Uniontyper har ingen runtime-overhead. De existerar endast vid kompilering och raderas under kompileringen.
Om prestanda Àr ett stort problem Àr uniontyper i allmÀnhet det bÀsta valet. Konstanta pÄstÄenden Àr ocksÄ ett bra alternativ, sÀrskilt om du behöver en nyckel-vÀrde-relation. Undvik att anvÀnda enums i prestandakritiska delar av din kod om du inte har en specifik anledning att göra det.
Globala implikationer och bÀsta praxis
NÀr du arbetar med projekt med internationella team eller globala anvÀndare Àr det avgörande att övervÀga lokalisering och internationalisering. HÀr Àr nÄgra bÀsta metoder för att anvÀnda enums och deras alternativ i ett globalt sammanhang:
- AnvÀnd beskrivande namn: VÀlj enum-medlemsnamn (eller konstanta pÄstÄende-nycklar) som Àr tydliga och otvetydiga, Àven för icke-engelsktalande. Undvik slang eller jargong.
- ĂvervĂ€g lokalisering: Om du behöver visa enum-medlemsnamn för anvĂ€ndare, övervĂ€g att anvĂ€nda ett lokaliseringsbibliotek för att tillhandahĂ„lla översĂ€ttningar för olika sprĂ„k. Till exempel, istĂ€llet för att direkt visa
Status.InProgress, kan du visai18n.t('status.in_progress'). - Undvik kulturspecifika antaganden: Var medveten om kulturella skillnader nÀr du definierar enum-vÀrden. Till exempel kan datumformat, valutasymboler och mÄttenheter variera betydligt mellan kulturer. Om du behöver representera dessa vÀrden, övervÀg att anvÀnda ett bibliotek som hanterar lokalisering och internationalisering.
- Dokumentera din kod: TillhandahÄll tydlig och koncis dokumentation för dina enums och deras alternativ, förklara deras syfte och anvÀndning. Detta kommer att hjÀlpa andra utvecklare att förstÄ din kod, oavsett deras bakgrund eller erfarenhet.
Exempel: Lokalisera anvÀndarroller
LÄt oss Äterbesöka exemplet med anvÀndarroller och övervÀga hur man lokaliserar rollnamnen för olika sprÄk.
// AnvÀnder konstanta pÄstÄenden med lokalisering
const UserRole = {
Admin: 'admin',
Editor: 'editor',
Viewer: 'viewer',
} as const;
type UserRoleType = typeof UserRole[keyof typeof UserRole];
// Lokaliseringsfunktion (med hjÀlp av ett hypotetiskt i18n-bibliotek)
function getLocalizedRoleName(role: UserRoleType, locale: string): string {
switch (role) {
case UserRole.Admin:
return i18n.t('user_role.admin', { locale });
case UserRole.Editor:
return i18n.t('user_role.editor', { locale });
case UserRole.Viewer:
return i18n.t('user_role.viewer', { locale });
default:
return 'OkÀnd roll';
}
}
// Exempel pÄ anvÀndning
const currentRole: UserRoleType = UserRole.Editor;
const localizedRoleName = getLocalizedRoleName(currentRole, 'fr-CA'); // Returnerar lokaliserat "Ăditeur" för franskkana.
console.log(`Aktuell roll: ${localizedRoleName}`);
I detta exempel anvÀnder vi en lokaliseringsfunktion för att hÀmta det översatta rollnamnet baserat pÄ anvÀndarens sprÄkinstÀllning. Detta sÀkerstÀller att rollnamnen visas pÄ anvÀndarens föredragna sprÄk.
Slutsats
TypeScript enums Ă€r en anvĂ€ndbar funktion, men de Ă€r inte alltid det bĂ€sta valet. Konstanta pĂ„stĂ„enden och uniontyper erbjuder livskraftiga alternativ som kan ge bĂ€ttre prestanda, oförĂ€nderlighet och kodunderhĂ„ll. Genom att förstĂ„ fördelarna och nackdelarna med varje tillvĂ€gagĂ„ngssĂ€tt kan du fatta vĂ€lgrundade beslut om vilken du ska anvĂ€nda i dina projekt. ĂvervĂ€g de specifika behoven för din applikation, ditt teams preferenser och den lĂ„ngsiktiga underhĂ„llbarheten av din kod. Genom att noggrant vĂ€ga dessa faktorer kan du vĂ€lja den bĂ€sta metoden för att definiera konstanter i dina TypeScript-projekt, vilket leder till renare, effektivare och mer underhĂ„llbara kodbaser.